﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Threading;
using System.Collections.ObjectModel;
using System.ComponentModel;
using QuantumBitDesigns.Core;
using System.IO;
using System.Xml.Serialization;
using CrazyWorship1.ListenerService;

namespace CrazyWorship1
{
    public class AssetManager : INotifyPropertyChanged
    {
        private static string SongFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//CrazyWorship";
        private ClientManager _clientManager;
        private SyncStatusList syncStatus;
        private static object songListLock = new object();
        private SongList songList;
        public AssetManager()
        {
            songList = new SongList(System.Windows.Threading.Dispatcher.CurrentDispatcher);
            NotifyPropertyChanged("SongList");
            syncStatus = new SyncStatusList();
            Thread thread = new Thread(new ThreadStart(mainloop));
            thread.Start();
        }
        public ObservableCollection<Song> SongList
        {
            get
            {
                if (songList == null)
                { return null; }
                return songList.ObservableCollection;
            }
        }
        public void SetClientManager(ClientManager clientManager)
        {
            _clientManager = clientManager;
        }

        private ClientManager ClientManager
        {
            get { return _clientManager; }
        }
        private void SendSong(SyncStatus s, BaseListenerClient cl)
        {
            if (cl.AssetsNeedsUpdate(s.FileName, s.LastUpdate))
            {
                //TODO SPECIAL CASE, FILE GOT UPDATED CHECK
                using (Stream stream = new FileStream(s.BaseFolder + s.FileName, FileMode.Open, FileAccess.Read))
                {
                    cl.AssetUpdate(s.FileName, s.LastUpdate, stream);
                }
            }
        }
        private void SyncSongs()
        {
            foreach (SyncStatus s in syncStatus)
            {
                if (_clientManager.ConnectedClients.Count != 0)
                {
                    if (s.Tries / _clientManager.ConnectedClients.Count < 3)
                    {
                        Status status = Status.Synced;
                        foreach (BaseListenerClient cl in _clientManager.ConnectedClients)
                        {
                            try
                            {
                                SendSong(s, cl);
                            }
                            catch
                            {
                                status = Status.NotSynced;
                                s.Tries++;
                            }
                        }
                        s.Status = status;
                    }
                    else
                        s.Status = Status.GivenUp;
                }
                else
                    s.Status = Status.NotSynced;
            }
        }

        private void mainloop()
        {
            LoadAllInfo();
            while (true)
            {
                //TODO:  CheckForUpdatesToSongs();
                SyncSongs();
                Thread.Sleep(100);
            }
        }
        private void LoadAllInfo()
        {
            //   TODO:         syncStatus = SyncStatusList.Load();

            if (!Directory.Exists(SongFolder))
                Directory.CreateDirectory(SongFolder);
            foreach (string d in Directory.GetDirectories(SongFolder))
            {
                if (File.Exists(d + "//song.xml"))
                {
                    Song s = new Song(d + "//song.xml");
                    SyncStatus ss = syncStatus.GetByFileName(SongFolder, d.Replace(SongFolder, "") + "//song.xml");
                    s.SyncStatus = ss;
                    syncStatus.Add(ss);
                    foreach (string f in s.Resources)
                    {
                        SyncStatus s2 = new SyncStatus(SongFolder, "/" + d.Replace(SongFolder, "") + "/" + f.Replace(SongFolder, ""));
                        ss.Children.Add(s2);
                        syncStatus.Add(s2);
                    }
                    songList.Add(s);
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
        public void ClientsUnloadSong()
        {
            foreach (BaseListenerClient c in _clientManager.ConnectedClients)
                c.SongUnload();
        }
        public void ClientsLoadSong(Song song)
        {
            foreach (BaseListenerClient c in _clientManager.ConnectedClients)
                c.SongLoad(song.SongFileName.Replace(SongFolder, ""));
        }
    }

    public class SyncStatusList : List<SyncStatus>
    {
        public SyncStatus GetByFileName(string basefolder, string filename)
        {
            foreach (SyncStatus d in this)
                if ((d.FileName == filename) && (d.BaseFolder == basefolder))
                    return d;
            SyncStatus t = new SyncStatus(basefolder, filename);
            this.Add(t);
            return t;
        }
    }
    public class SyncStatus : INotifyPropertyChanged
    {
        private Status _status;
        private string _baseFolder;
        DateTime _lastUpdate;
        private string _fileName;
        public int Tries;
        public SyncStatusList Children = new SyncStatusList();
        public event PropertyChangedEventHandler PropertyChanged;
        private SyncStatus()
        {
        }
        public SyncStatus(string baseFolder, string fileName)
        {
            _baseFolder = baseFolder;
            _fileName = fileName;
            _lastUpdate = File.GetLastWriteTime(baseFolder + fileName);
            Status = Status.Loaded;
        }

        public Status Status
        {
            get
            { return _status; }
            set
            {
                _status = value;
                NotifyPropertyChanged("Status");
            }
        }
        public DateTime LastUpdate
        {
            get
            { return _lastUpdate; }
        }
        public string BaseFolder
        {
            get
            { return _baseFolder; }
        }
        public string FileName
        {
            get { return _fileName; }
        }

        private void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }

}
